﻿#include "tabledataanalysis.h"
#include "mytablewidget.h"
#include "scatterplotwidget.h"
#include "histogramwidget.h"
#include "multicurvewidget.h"

TableDataAnalysis::TableDataAnalysis(QWidget *parent)
    : QMainWindow(parent)
{
    setupUI();
}

TableDataAnalysis::~TableDataAnalysis()
{}

void TableDataAnalysis::setupUI() {
    this->setGeometry(300, 300, 1200, 600);
    QToolBar* toolBar = addToolBar("main toolbar");

    /*int fontSize = 16;
    QFont font("Arial", fontSize, QFont::Bold);
    toolBar->setFont(font);*/

    btnOpenParamTest = new QPushButton("OpenParamTest", this);
    btnOpenFordSim = new QPushButton("OpenFordSim", this);
    btnOpenFordSim->setEnabled(false);
    btnHistogram = new QPushButton("Histogram", this);
    //btnBoxPlot = new QPushButton("BoxPlot", this);
    btnSpreadSheet = new QPushButton("Spreadsheet", this);
    btnPlotScattor = new QPushButton("Scatter", this);
    btnMultiCurves = new QPushButton("MultiCurves", this);
    btnMultiCurves->setEnabled(false);
    toolBar->addWidget(btnOpenParamTest);
    toolBar->addWidget(btnOpenFordSim);
    toolBar->addWidget(btnHistogram);
    //toolBar->addWidget(btnBoxPlot);
    toolBar->addWidget(btnSpreadSheet);
    toolBar->addWidget(btnPlotScattor);
    toolBar->addWidget(btnMultiCurves);

    connect(btnOpenParamTest, &QPushButton::clicked, this, &TableDataAnalysis::onOpenFile);
    connect(btnOpenFordSim, &QPushButton::clicked, this, &TableDataAnalysis::onOpenFordSim);
    connect(btnHistogram, &QPushButton::clicked, this, &TableDataAnalysis::onHistogram);
    //connect(btnBoxPlot, &QPushButton::clicked, this, &TableDataAnalysis::onBoxPlot);
    connect(btnSpreadSheet, &QPushButton::clicked, this, &TableDataAnalysis::onSpreadSheet);
    connect(btnPlotScattor, &QPushButton::clicked, this, &TableDataAnalysis::onScatter);
    connect(btnMultiCurves, &QPushButton::clicked, this, &TableDataAnalysis::onMultiCurves);

}

void TableDataAnalysis::loadAndAnalyzeData(const QString& filePath) {
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::critical(this, "Error", "Unable to open file");
        return;
    }
    columnData.clear();

    QTextStream in(&file);
    QString line;
    if (!in.atEnd()) {
        // Read the first line as column names
        line = in.readLine();
        columnNames = line.split(QRegExp("\\s+|\t"), Qt::SkipEmptyParts);
    }

    QVector<QVector<double>> tempData;  // Temporary container for all rows
    int rowCount = 0;
    while (!in.atEnd()) {
        line = in.readLine();
        ++rowCount;
        QStringList values = line.split(QRegExp("\\s+|\t"), Qt::SkipEmptyParts);
        if (values.size() == columnNames.size()) {
            QVector<double> rowData;
            bool validRow = true;
            for (int i = 0; i < values.size(); ++i) {
                if (!values[i].isEmpty()) {
                    bool ok;
                    double value = values[i].toDouble(&ok);
                    if (ok) {
                        rowData.append(value);
                    }
                    else {
                        QMessageBox::critical(this, "Error", "Invalid data format at line " + QString::number(rowCount));
                        validRow = false;
                        break;
                    }
                }
            }
            if (validRow) {
                //if (rowData[1] < 1e6)
                    tempData.append(rowData);
            }
        }
    }
    file.close();

    // Sort tempData by the second column (index 1)
    std::sort(tempData.begin(), tempData.end(), [](const QVector<double>& a, const QVector<double>& b) {
        return a[1] < b[1];  // Change < to > for descending order
        });

    // Transpose tempData into columnData
    if (!tempData.isEmpty()) {
        columnData.resize(tempData[0].size());
        for (const auto& row : tempData) {
            for (int i = 0; i < row.size(); ++i) {
                columnData[i].append(row[i]);
            }
        }
    }
    QMessageBox::information(this, "Information", "Data loaded successfully. " + QString::number(rowCount) + " rows are read.");
    // Update btnOpenFordSim enable status
    btnOpenFordSim->setEnabled(true);
}


void TableDataAnalysis::onOpenFile() {
    QString filePath = QFileDialog::getOpenFileName(this, "Open File", QDir::homePath());
    if (!filePath.isEmpty()) {
        loadAndAnalyzeData(filePath);
    }
}

void TableDataAnalysis::onOpenFordSim()
{
    
    QString filePath = QFileDialog::getOpenFileName(this, "Open File", QDir::homePath(), "Text Files (*.txt)|data file(*.data)");
    if (filePath.isEmpty()) {
        return;
    }
    QFileInfo fileInfo(filePath);
    QDir::setCurrent(fileInfo.path());
    qDebug() << "Current path:" << QDir::currentPath();

    QString fileName = fileInfo.fileName();
    modelSim = std::make_shared<ModelSim>(fileName.toStdString());
    modelSim->ReadOptionFile();
    modelSim->writeSeaLevelCurve("sealevel.txt");

    if (modelSim->parmInv.pUsedNum() + 2 != columnData.size()) {
        QMessageBox::warning(this, "Error", "The number of columns in the data file is not equal to the number of parameters used in the model.");
    }
    int i = 0;
    for (auto p : modelSim->parmInv.params) {
        if (p.pxUseLabel == 0) {
            continue;
        }
        if (p.pxName != columnNames[i + 2].toStdString()) {
            QString message = "The column name in the data file is not equal to the parameter name in the model. " 
                + QString::number(i + 2) + "th column name is " + columnNames[i + 2] + " but the parameter name is " 
                + QString::fromStdString(p.pxName);
            QMessageBox::critical(this, "Error", message);
            return;
        }
        i++;
    }
    btnMultiCurves->setEnabled(true);
}

void TableDataAnalysis::onHistogram()
{
    HistogramWidget *hist = new HistogramWidget(columnData, columnNames, this);
    hist->setWindowTitle("Histogram");
    //hist->resize(800, 600);
    //hist->show();
    setCentralWidget(hist);
}

void TableDataAnalysis::onBoxPlot()
{
}

void TableDataAnalysis::onSpreadSheet()
{ 
    // 创建 QTableWidget 并设置列名
    auto* tableWidget = new MyTableView();
    tableWidget->setTableData(columnData, columnNames);
    tableWidget->setWindowTitle("Table Data Analysis");
    /*tableWidget->resize(800, 600);
    tableWidget->show();*/
    this->setCentralWidget(tableWidget);
}

void TableDataAnalysis::onScatter()
{
    auto scattor = new ScatterPlotWidget(columnData, columnNames, this);
    scattor->setWindowTitle("Scatter Plot");
    //scattor->resize(800, 600);
    //scattor->show();
    this->setCentralWidget(scattor);
}

void TableDataAnalysis::onMultiCurves()
{
    //if (modelSim == nullptr) {
    //    QMessageBox::critical(this, "Error", "Please open FordSim data first! now show demo curves");

    //    int pointNum = 100;
    //    QVector<double> xData(pointNum);

    //    for (int i = 0; i < pointNum; i++) {
    //        xData[i] = 100 + i * 2;
    //    }
    //    int curveNum = 10;
    //    QVector<QString> curveNames(curveNum);
    //    QVector<QVector<double>>yData(curveNum, QVector<double>(pointNum));
    //    for (int j = 0; j < curveNum; j++) {
    //        int pha = rand() % 5 + 2;
    //        for (int i = 0; i < pointNum; i++) {
    //            int amp = rand() % (curveNum * 2) + 5;
    //            yData[j][i] = amp * sin(i * pha * 0.1);
    //        }
    //        curveNames[j] = "curve_" + QString::number(j);
    //    }
    //    QVector<double> aveCurves(pointNum);
    //    for (int i = 0; i < pointNum; i++) {
    //        double sum = 0;
    //        for (int j = 0; j < curveNum; j++) {
    //            sum += yData[j][i];
    //        }
    //        aveCurves[i] = sum / curveNum;
    //    }
    //    yData.append(aveCurves);
    //    curveNames.append("average");

    //    auto multiCurves = new MultiCurveWidget(xData, yData, curveNames, this);
    //    multiCurves->setWindowTitle("Multi Curves");
    //    //multiCurves->resize(800, 600);
    //    //multiCurves->show();
    //    this->setCentralWidget(multiCurves);
    //}
    //else 
    {
        auto theDims = modelSim->theDims;
        int pointNum = theDims.TotStep();
        QVector<double> xData(pointNum);
        for (int i = 0; i < pointNum; i++) {
            xData[i] = theDims.StartYr() - i * theDims.dt();
        }
        if (modelSim->parmInv.pUsedNum() + 2 != columnData.size()) {
            QMessageBox::critical(this, "Error", "The number of columns in the data file is not equal to the number of parameters used in the model.");
            return;
        }
        int paramNum = modelSim->parmInv.pUsedNum();
        int curveNum = columnData[0].size();
        QVector<QString> curveNames(curveNum);
        for (int j = 0; j < curveNum; j++) {
            curveNames[j] = "curve_" + QString::number(j);
        }
        QVector<QVector<double>> yData(curveNum, QVector<double>(pointNum));
        for (int j = 0; j < curveNum; j++) {
            vector<double> param(paramNum);
            for (int i = 0; i < paramNum; i++) {
                param[i] = columnData[i+2][j];
            }
            modelSim->updateUnparameters(param.data(), param.size());
            for (int i = 0; i < pointNum; i++) {
                yData[j][i] = modelSim->forwsPr.eUPr.SeaLcurve.Dat[i+1];
            }
        }
        QVector<double> aveCurves(pointNum);
        for (int i = 0; i < pointNum; i++) {
            double sum = 0;
            for (int j = 0; j < curveNum; j++) {
                sum += yData[j][i];
            }
            aveCurves[i] = sum / curveNum;
        }
        yData.append(aveCurves);
        curveNames.append("average");
        auto multiCurves = new MultiCurveWidget(xData, yData, curveNames, this);
        multiCurves->setWindowTitle("Multi Curves");
        //multiCurves->resize(800, 600);
        //multiCurves->show();
        this->setCentralWidget(multiCurves);
    }

    
}



